package com.boot.message.netty.server.receiver;

import com.boot.message.netty.server.NettyServerProperties;
import com.boot.message.netty.server.handler.AbstractServerChannelInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

/**
 * @author 霜寒 <1621856595@qq.com>
 * @description Netty服务端对外接口
 * @date 2019/11/21 13:35
 **/
@Slf4j
public class NettyServerReceiver {

    private final NettyServerProperties nettyServerProperties;

    private final AbstractServerChannelInitializer<SocketChannel> serverChannelInitializer;

    public NettyServerReceiver(NettyServerProperties nettyServerProperties, AbstractServerChannelInitializer<SocketChannel> serverChannelInitializer) {
        this.nettyServerProperties = nettyServerProperties;
        this.serverChannelInitializer = serverChannelInitializer;
    }

    private InetSocketAddress inetSocketAddress;

    private NioEventLoopGroup bossGroup;

    private NioEventLoopGroup workerGroup;

    private InetSocketAddress getSocketAddress() {
        if (inetSocketAddress == null) {
            if (nettyServerProperties.getPort() == 0) {
                throw new RuntimeException("未设置 Netty 服务端口，无法启动服务！");
            } else {
                inetSocketAddress = new InetSocketAddress(nettyServerProperties.getPort());
            }
        }
        return inetSocketAddress;
    }

    private NioEventLoopGroup getBossGroup() {
        if (bossGroup == null) {
            bossGroup = new NioEventLoopGroup(nettyServerProperties.getBossCount());
        }
        return bossGroup;
    }

    private NioEventLoopGroup getWorkerGroup() {
        if (workerGroup == null) {
            workerGroup = new NioEventLoopGroup(nettyServerProperties.getWorkerCount());
        }
        return workerGroup;
    }

    private ServerBootstrap serverBootstrap() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(getBossGroup(), getWorkerGroup())
                .channel(NioServerSocketChannel.class)
                .childHandler(serverChannelInitializer);
        bootstrap.option(ChannelOption.SO_BACKLOG, nettyServerProperties.getBacklog())
                .option(ChannelOption.SO_SNDBUF, nettyServerProperties.getBuffer())
                .option(ChannelOption.SO_RCVBUF, nettyServerProperties.getBuffer())
                .childOption(ChannelOption.SO_KEEPALIVE, nettyServerProperties.isKeepAlive());
        return bootstrap;
    }

    private ChannelFuture channelFuture;

    public NettyServerReceiver start() throws Exception {
        if (nettyServerProperties.isEnable()) {
            log.info("开启 Netty 服务，地址：{}:{}", getSocketAddress().getHostString(),
                    getSocketAddress().getPort());
            channelFuture = serverBootstrap().bind(getSocketAddress()).sync();
        }
        return this;
    }

    public void stop() {
        if (nettyServerProperties.isEnable()) {
            channelFuture.channel().closeFuture();
            getBossGroup().shutdownGracefully();
            getWorkerGroup().shutdownGracefully();
            log.info("关闭 Netty 服务...");
        }
    }

}
